/*
 * Copyright (c) Huawei Technologies Co., Ltd. 2019-2019.
 * Description: rtos_mce_trap.c
 * Author: xiaojiangfeng
 * Create: 2019-06-03
 */

#include <linux/rcupdate.h>
#include <asm/rtos_mce_trap.h>

static int (*rtos_mce_hook)(struct pt_regs *, int);

int register_mce_trap_hook(int (*hook)(struct pt_regs *, int))
{
	int (*exist_hook)(struct pt_regs *, int) = NULL;

	if (!hook) {
		pr_err("%s hook is null\n", __func__);
		return -EINVAL;
	}

	exist_hook = rcu_dereference(rtos_mce_hook);
	if (exist_hook) {
		pr_err("%s mce_hook is exist, unregister first\n", __func__);
		return -EEXIST;
	}

	rcu_assign_pointer(rtos_mce_hook, hook);
	return 0;
}
EXPORT_SYMBOL(register_mce_trap_hook);

void unregister_mce_trap_hook(void)
{
	int (*exist_hook)(struct pt_regs *, int) = NULL;

	exist_hook = rcu_dereference(rtos_mce_hook);
	if (!exist_hook) {
		pr_err("%s mce_hook is null\n", __func__);
		return;
	}

	rcu_assign_pointer(rtos_mce_hook, NULL);
}
EXPORT_SYMBOL(unregister_mce_trap_hook);

/*
 * Router use the judgment to put the exception into user mode
 * to determine whether it is the machine check caused by the hot plug of card.
 * If yes, skip and do not reset the system.
 */
int call_rtos_mce_hook(struct pt_regs *regs, int recover)
{
	int ret = 0;
	int (*exist_hook)(struct pt_regs *, int) = NULL;

	rcu_read_lock();
	exist_hook = rcu_dereference(rtos_mce_hook);
	if (exist_hook)
		ret = exist_hook(regs, recover);

	rcu_read_unlock();

	return ret;
}

